package cn.aitrox.ry.service.oss.sdk;

import cn.aitrox.ry.bean.RespResult;
import cn.aitrox.ry.common.exception.CustomBizException;
import cn.aitrox.ry.service.oss.bean.UrlValidResult;
import cn.aitrox.ry.service.oss.constant.ErrorConstant;
import cn.aitrox.ry.service.oss.dto.FileRestoreInfoDto;
import cn.aitrox.ry.util.JSONUtil;
import cn.aitrox.ry.util.LogUtil;
import cn.ucloud.ufile.UfileClient;
import cn.ucloud.ufile.api.object.DownloadFileApi;
import cn.ucloud.ufile.api.object.GetFileApi;
import cn.ucloud.ufile.api.object.ObjectConfig;
import cn.ucloud.ufile.auth.ObjectAuthorizer;
import cn.ucloud.ufile.bean.CopyObjectResultBean;
import cn.ucloud.ufile.bean.DownloadFileBean;
import cn.ucloud.ufile.bean.DownloadStreamBean;
import cn.ucloud.ufile.bean.ObjectListBean;
import cn.ucloud.ufile.bean.ObjectProfile;
import cn.ucloud.ufile.bean.PutObjectResultBean;
import cn.ucloud.ufile.bean.base.BaseObjectResponseBean;
import cn.ucloud.ufile.exception.UfileClientException;
import cn.ucloud.ufile.exception.UfileServerException;
import cn.ucloud.ufile.util.MimeTypeUtil;
import cn.ucloud.ufile.util.StorageType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;

@Component
public class UcloudOssSdk implements OssSdk {

    private static final Logger LOG = LoggerFactory.getLogger(UcloudOssSdk.class);

    private static final String ARCHIVE = "ARCHIVE";

    public static final int FILE_GET_BUFFER_SIZE = 4096 << 10;
    public static final long CONNECT_TIME_OUT = 3000;
    public static final long READ_TIME_OUT = 600000;

    @Autowired
    @Qualifier("ucloudObjectAuthorization")
    private ObjectAuthorizer objectAuthorizer;

    @Qualifier("ucloudObjectConfigLan")
    @Autowired
    private ObjectConfig objectConfigLan;

    @Qualifier("ucloudObjectConfigWan")
    @Autowired
    private ObjectConfig objectConfigWan;

    @Value("${ucloud.bucket:}")
    private String bucket;

    public RespResult<FileRestoreInfoDto> getDownloadUrl(String resourceKey, Integer expireTime) {
        String urlLan;
        String urlWan;
        try {
            urlLan = UfileClient.object(objectAuthorizer, objectConfigLan).getDownloadUrlFromPrivateBucket(resourceKey, bucket, expireTime).createUrl();
            urlWan = UfileClient.object(objectAuthorizer, objectConfigWan).getDownloadUrlFromPrivateBucket(resourceKey, bucket, expireTime).createUrl();
            return RespResult.ok(new FileRestoreInfoDto(resourceKey, urlLan, urlWan));
        } catch (UfileClientException e) {
            LOG.error(LogUtil.genException(e, "ucloud getDownloadUrl call UfileClientException", "key", resourceKey, "expireTime", expireTime + ""));
            return RespResult.error(e.getMessage());
        }
    }

    public RespResult copyFile(String srcKey, String dstKey) {
        try {
            CopyObjectResultBean resultBean = UfileClient.object(objectAuthorizer, objectConfigLan).copyObject(bucket, srcKey).copyTo(bucket, dstKey).execute();
            if (resultBean.getRetCode() == 0) {
                return RespResult.ok();
            }
            LOG.error(LogUtil.gen("ucloud copyFile response fail", "retCode", resultBean.getRetCode() + "", "resMsg", resultBean.getMessage() + "", "srcKey", srcKey, "dstKey", dstKey));
            return RespResult.error(ErrorConstant.COPY_FILE_ERR);
        } catch (UfileClientException e) {
            LOG.error(LogUtil.genException(e, "ucloud copyFile call UfileClientException", "srcKey", srcKey, "dstKey", dstKey));
            return RespResult.error(e.getMessage());
        } catch (UfileServerException e) {
            LOG.error(LogUtil.genException(e, "ucloud copyFile call UfileServerException", "srcKey", srcKey, "dstKey", dstKey));
            return RespResult.error(e.getMessage());
        }
    }

    public RespResult archive(String resourceKey) {
        try {
            BaseObjectResponseBean response = UfileClient.object(objectAuthorizer, objectConfigLan).switchStorageType(bucket, resourceKey).turnTypeTo(StorageType.ARCHIVE).execute();
            LOG.info(LogUtil.gen("ucloud archive call", "response", JSONUtil.toJson(response, BaseObjectResponseBean.class), "key", resourceKey));
            if (response.getRetCode() == 0) {
                return RespResult.ok();
            }
            return RespResult.error(ErrorConstant.ARCHIVE_FILE_ERR);
        } catch (UfileClientException e) {
            LOG.error(LogUtil.genException(e, "ucloud archive call UfileClientException", "key", resourceKey));
            return RespResult.error(e.getMessage());
        } catch (UfileServerException e) {
            LOG.error(LogUtil.genException(e, "ucloud archive call UfileServerException", "key", resourceKey));
            return RespResult.error(e.getMessage());
        }
    }

    public RespResult putFileByIs(String resourceKey, InputStream is, String oringinFileName) {
        try {
            PutObjectResultBean resultBean = UfileClient.object(objectAuthorizer, objectConfigLan).putObject(is, MimeTypeUtil.getMimeType(oringinFileName)).nameAs(resourceKey).toBucket(bucket).execute();
            if (resultBean.getRetCode() == 0) {
                return RespResult.ok();
            }
            return RespResult.error(ErrorConstant.PUT_FILE_ERR);
        } catch (UfileClientException e) {
            LOG.error(LogUtil.genException(e, "ucloud putFileByIs call UfileClientException", "key", resourceKey, "fileName", oringinFileName));
            return RespResult.error(e.getMessage());
        } catch (UfileServerException e) {
            LOG.error(LogUtil.genException(e, "ucloud putFileByIs call UfileServerException", "key", resourceKey, "fileName", oringinFileName));
            return RespResult.error(e.getMessage());
        }
    }

    public RespResult putFile(String resourceKey, File file) {
        if (!file.exists()) {
            throw new CustomBizException("文件不存在");
        }
        try {
            PutObjectResultBean resultBean = UfileClient.object(objectAuthorizer, objectConfigLan).putObject(file, MimeTypeUtil.getMimeType(file)).nameAs(resourceKey).toBucket(bucket).execute();
            if (resultBean.getRetCode() == 0) {
                return RespResult.ok();
            }
            return RespResult.error(ErrorConstant.PUT_FILE_ERR);
        } catch (UfileClientException e) {
            LOG.error(LogUtil.genException(e, "ucloud putFile call UfileClientException", "key", resourceKey, "filePath", file.getAbsolutePath()));
            return RespResult.error(e.getMessage());
        } catch (UfileServerException e) {
            LOG.error(LogUtil.genException(e, "ucloud putFile call UfileServerException", "key", resourceKey, "filePath", file.getAbsolutePath()));
            return RespResult.error(e.getMessage());
        }
    }

    @Override
    public RespResult deleteFile(String key) {
        try {
            BaseObjectResponseBean execute = UfileClient.object(objectAuthorizer, objectConfigLan).deleteObject(key, bucket).execute();
            if (execute.getRetCode() == 0) {
                return RespResult.ok();
            }
            return RespResult.error(ErrorConstant.PUT_FILE_ERR);
        } catch (UfileClientException e) {
            LOG.error(LogUtil.genException(e, "ucloud deleteFile call UfileClientException", "key", key));
            return RespResult.error(e.getMessage());
        } catch (UfileServerException e) {
            LOG.error(LogUtil.genException(e, "ucloud deleteFile call UfileClientException", "key", key));
            return RespResult.error(e.getMessage());
        }
    }

//    public RespResult<String> getUrl(String resourceKey, NetworkEnum networkEnum) {
//        if (null == networkEnum) {
//            throw new CustomBizException("network不能为空");
//        }
//        try {
//            String url;
//            if (networkEnum == NetworkEnum.WAN) {
//                url = UfileClient.object(objectAuthorizer, objectConfigWan).getDownloadUrlFromPrivateBucket(resourceKey, bucket, 86400).createUrl();
//            } else {
//                url = UfileClient.object(objectAuthorizer, objectConfigLan).getDownloadUrlFromPrivateBucket(resourceKey, bucket, 86400).createUrl();
//            }
//            return RespResult.ok(url);
//        } catch (UfileClientException e) {
//            LOG.error(LogUtil.genException(e, "ucloud getUrl call UfileClientException", "key", resourceKey, "network", networkEnum.getType()));
//            return RespResult.error(e.getMessage());
//        }
//    }

    public RespResult restore(String resourceKey) {
        try {
            BaseObjectResponseBean response = UfileClient.object(objectAuthorizer, objectConfigLan).objectRestore(resourceKey, bucket).execute();
            LOG.info(LogUtil.gen("ucloud restore call", "response", JSONUtil.toJson(response, BaseObjectResponseBean.class), "key", resourceKey));
            if (response.getRetCode() == 0) {
                return RespResult.ok();
            }
            return RespResult.error(ErrorConstant.RESTORE_ERR);
        } catch (UfileClientException e) {
            LOG.error(LogUtil.genException(e, "ucloud restore call UfileClientException", "key", resourceKey));
            return RespResult.error(e.getMessage());
        } catch (UfileServerException e) {
            LOG.error(LogUtil.genException(e, "ucloud restore call UfileServerException", "key", resourceKey));
            return RespResult.error(e.getMessage());
        }
    }

    public RespResult checkAcessable(String downloadUrl, Boolean printErr) {
        InputStream is = null;
        try {
            DownloadStreamBean executeResult = UfileClient.object(objectAuthorizer, objectConfigLan).getStream(downloadUrl).execute();
            is = executeResult.getInputStream();
            return RespResult.ok();
        } catch (UfileClientException e) {
            if (printErr) {
                LOG.error(LogUtil.genException(e, "ucloud getStream call UfileClientException", "downloadUrl", downloadUrl));
            }
            return RespResult.error(e.getMessage());
        } catch (UfileServerException e) {
            if (printErr) {
                String errMsg = e.getMessage();
                LOG.error(LogUtil.gen("ucloud getStream call UfileServerException", "downloadUrl", downloadUrl, "errMsg", null == errMsg ? "null" : errMsg));
            }
            return RespResult.error(e.getMessage());
        } finally {
            if (null != is) {
                try {
                    is.close();
                } catch (IOException e) {
                }
            }
        }
    }

    public RespResult<File> getFile(String resourceKey, String toFilePath) {
        try {
            File toFile = new File(toFilePath);
            String parentPath = toFile.getParent();
            String fileName = toFile.getName();
            ObjectProfile profile = new ObjectProfile();
            profile.setBucket(bucket);
            profile.setKeyName(resourceKey);

            DownloadFileApi downloadFileApi = UfileClient.object(objectAuthorizer, objectConfigLan).downloadFile(profile);
            downloadFileApi.setConnTimeOut(CONNECT_TIME_OUT); // 3秒
            downloadFileApi.setReadTimeOut(READ_TIME_OUT); // 300秒
            downloadFileApi.setBufferSize(FILE_GET_BUFFER_SIZE); // 4M
            DownloadFileBean execute = downloadFileApi.saveAt(parentPath, fileName).execute();
            return RespResult.ok(execute.getFile());
        } catch (UfileClientException e) {
            LOG.error(LogUtil.genException(e, "ucloud getFile call UfileClientException", "key", resourceKey, "toFilePath", toFilePath));
            return RespResult.error(e.getMessage());
        }
    }

    public RespResult<File> getFileByDownloadUrl(String downloadUrl, String toFilePath) {
        try {
            File toFile = new File(toFilePath);
            String parentPath = toFile.getParent();
            String fileName = toFile.getName();
            GetFileApi getFileApi = UfileClient.object(objectAuthorizer, objectConfigLan).getFile(downloadUrl);
            getFileApi.setConnTimeOut(CONNECT_TIME_OUT); // 3秒
            getFileApi.setReadTimeOut(READ_TIME_OUT); // 600秒
            getFileApi.setBufferSize(FILE_GET_BUFFER_SIZE); // 4M
            DownloadFileBean execute = getFileApi.saveAt(parentPath, fileName).execute();
            return RespResult.ok(execute.getFile());
        } catch (UfileClientException e) {
            LOG.error(LogUtil.genException(e, "ucloud getFileByDownloadUrl call UfileClientException", "key", downloadUrl, "toFilePath", toFilePath));
            return RespResult.error(e.getMessage());
        } catch (UfileServerException e) {
            LOG.error(LogUtil.genException(e, "ucloud getFileByDownloadUrl call UfileServerException", "key", downloadUrl, "toFilePath", toFilePath));
            return RespResult.error(e.getMessage());
        }
    }

    public RespResult<Long> fileSize(String resourceKey) {
        long fileSize = -1;
        try {
            ObjectListBean executeResult = UfileClient.object(objectAuthorizer, objectConfigLan).objectList(bucket).withPrefix(resourceKey).dataLimit(1).execute();
            if (null != executeResult.getObjectList() && executeResult.getObjectList().size() > 0) {
                fileSize = executeResult.getObjectList().get(0).getSize();
            }
        } catch (UfileClientException e) {
            LOG.error(LogUtil.genException(e, "ucloud objectList call UfileClientException", "key", resourceKey));
            return RespResult.error(e.getMessage());
        } catch (UfileServerException e) {
            LOG.error(LogUtil.genException(e, "ucloud objectList call UfileClientException", "key", resourceKey));
            return RespResult.error(e.getMessage());
        }
        LOG.info(LogUtil.gen("fileSize = " + fileSize, "key", resourceKey));
        if (fileSize == -1) {
            return RespResult.error(ErrorConstant.GET_FILE_SIZE_ERR);
        }
        return RespResult.ok(fileSize);
    }

    @Override
    public RespResult moveFile(String key, String filePath) {
        File file = new File(filePath);
        RespResult respResult = this.putFile(key, file);
        if (respResult._isOk()) {
            file.delete();
        }
        return respResult;
    }

    @Override
    public UrlValidResult validUrl(String url) {
        return null;
    }
}
